package com.itheima.springboottlias.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//通知类型的特点
@Slf4j
@Component
@Aspect//1.编写切面类
public class AspectType {
    //spring提供提取公共的切入点表达式的注解:@Pointcut
    @Pointcut("execution(* com.itheima.springboottlias.controller.DeptController.queryAll(..))")
    //公共的切入点表达式,可以在外部的其他切面类中使用
    //私有的只能在当前切面类中使用
    public void pt1(){} //公共的,无返回值,无参数的,无具体代码的


/*
* 切入点表达式的写法一:方法签名定位方法
* execution(修饰符 返回值类型 包名.类名.方法名(参数列表) throws 异常)
* 1.其中修饰符可以省略 表示任意修饰符
*   包名.类名可以省略 表示当前包及其子包下的所有类(不推荐省略)
*   异常可以省略 表示任意异常
* 2.execution 可以使用逻辑运算符: && || !
* 3.execution 可以使用通配符:
*     * 表示任意单个字符 ,返回值,包名,类名,方法名,参数列表
*    包/类/方法名称一部分
*   ..:表示任意多个字符,任意层级的包-,任意的类型/任意数量的参数(包括无参数)
* 4.注意:不推荐大量使用通配符,尽量使用精确的表达式
*
*
* 切入点表达式写法二:指定的注解,匹配目标方法
*            @annotation(com.itheima.springboottlias.anno.MyLog)
*           在需要增强的方法上加上注解@MyLog即可
*
* 方法一和方法二可以一起使用,其中使用逻辑运算符连接
* */


    //2.编写通知方法:前置通知
    @Before("pt1()")//3.通知类型+切入点表达式
    public void before(){
        log.info("前置通知");
    }
    @After("pt1()")//3.通知类型+切入点表达式
    public void after(){
        log.info("后置通知");
    }
    @AfterReturning("execution(* com.itheima.springboottlias.controller.DeptController.queryAll(..))")//3.通知类型+切入点表达式
    public void afterReturning(){
        log.info("返回后通知");
    }
    @AfterThrowing("execution(* com.itheima.springboottlias.controller.DeptController.queryAll(..))")//3.通知类型+切入点表达式
    public void afterThrowing(){
        log.info("异常后通知");
    }
    //环绕通知:功能最强大的通知类型
    @Around("execution(* com.itheima.springboottlias.controller.DeptController.queryAll(..))")//3.通知类型+切入点表达式
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //自行调用目标方法
        Object proceed= null;
        try {
            log.info("环绕通知 前置通知");
            proceed = pjp.proceed();
            log.info("环绕通知 返回后通知");
        } catch (Throwable e) {
            log.info("环绕通知 异常后通知");
            throw new RuntimeException(e);
        }finally {
            log.info("环绕通知 后置通知");
        }

        log.info("环绕通知");
        return proceed;
    }
}
